#include "StdAfx.h"
#include "Route.h"

//===========================================================================
Route::Route(
    Route *    parent,
    IBoard *   board,
    EPieceType piece,
    Position   position
)   : m_parent( parent )
    , m_board( board )
    , m_piece( piece )
    , m_position( position )
    , m_left( NULL )
    , m_right( NULL )
    , m_depth( 0 )
{
    assert( m_board );
    assert( this->m_board->IsValidPosition( this->m_position ) );
}

//===========================================================================
Route::Route(
    const Route & route
) {
    this->m_parent   = route.m_parent;
    this->m_board    = route.m_board;
    this->m_piece    = route.m_piece;
    this->m_position = route.m_position;
    this->m_depth    = route.m_depth;
    this->m_left     = route.m_left
                     ? new Route( *route.m_left )
                     : NULL;
    this->m_right    = route.m_right
                     ? new Route( *route.m_right )
                     : NULL;
}

//===========================================================================
Route::~Route(void)
{
    this->CleanUp();
}

//===========================================================================
void Route::CleanUp( void )
{
    this->m_board  = NULL;
    this->m_depth  = 0;
    this->m_parent = NULL;
    this->m_piece  = EPT_NONE;
    
    if( this->m_left ) {
        delete this->m_left;
        this->m_left = NULL;
    }

    if( this->m_right ) {
        delete this->m_right;
        this->m_right = NULL;
    }
}

//===========================================================================
void Route::IncreaeDepth(
    unsigned int depth
) {
    this->m_depth += depth;
    if( this->m_parent )
        this->m_parent->IncreaeDepth( depth );
}

//===========================================================================
unsigned int Route::SearchAllRoutes(
    bool jumped /* = false */
) {
    const EPieceType * piece = this->m_board->GetPiece( this->m_position );
    if( !piece )
        return 0;
    if( !jumped && !( !this->m_parent && this->m_piece == *piece ) )
        return 0;

    const unsigned int nodes = 2;
    Node node[ nodes ] = {
        Node( EC_LEFT, &this->m_left ), Node( EC_RIGHT, &this->m_right )
    };
    unsigned int maxDepth = 0;
    for( unsigned int i = 0; i < nodes; i++ ) {
        if( this->GetDestPosition(
                this->m_position,
                node[ i ].course,
                node[ i ].dest
        ) ) {
            Route * route = new Route(
                this,
                this->m_board,
                this->m_piece,
                node[ i ].dest
            );
            *node[ i ].route = route;
            
            unsigned int depth = route->GetPosition().GetX() - this->GetPosition().GetX();
            route->SearchAllRoutes(
                  depth > 1
                ? true
                : false
            );
            if( maxDepth < depth )
                maxDepth = depth;
        }
    }

    if( this->m_left || this->m_right )
        this->IncreaeDepth( maxDepth );
    
    return this->m_depth;
}

//===========================================================================
const EPieceType * Route::GetDest(
    const IPosition & position,
          ECourse     course,
          Position &  dest
) {
    unsigned int y = position.GetY();
    switch( course )
    {
        case EC_LEFT  : y += 1; break;
        case EC_RIGHT : y -= 1; break;
        default : return NULL;
    }
    unsigned int x = position.GetX() + 1;
    dest.Set( x, y );

    const EPieceType * piece = this->m_board->GetPiece( dest );
    return piece;
}

//===========================================================================
bool Route::GetDestPosition(
    const IPosition & position,
          ECourse     course,
          Position &  dest
) {
    const EPieceType * piece = this->GetDest(
        position,
        course,
        dest
    );
    if( !piece || this->m_piece == *piece )
        return false;
    
    if( EPT_NONE == *piece )
        if( !this->m_parent )
            return true;
        else
            return false;

    Position dest2;
    piece = this->GetDest(
        dest,
        course,
        dest2
    );
    if( !piece || EPT_NONE != *piece )
        return false;
    
    dest = dest2;
    return true;
}